# include "chainingHashMap.h"

ChainingHashMap * newChainingHashMap (int size) {
        ChainingHashMap *new = (ChainingHashMap *) malloc(sizeof(ChainingHashMap)); 
        if (!new) logMessage("util.hashs","chainingHashMap","newChainingHashMap","Memória Insuficiente - HashMap",CRITICAL);
        new->list = (LinkedList **) malloc(sizeof(LinkedList *)*(size+1));
        if (!new->list) logMessage("util.hashs","chainingHashMap","newChainingHashMap","Memória Insuficiente - List",CRITICAL);
	int i;
	for (i=0;i<size+1;i++) new->list[i] = NULL;
        new->size = size;
        new->hash = NULL;
        new->eq = NULL;
        return new;
}

int putChaining (ChainingHashMap *map, void *key, void *data) {
        int k = (map->hash)(key,map->size);
        int found = 0;
        LinkedList *aux;
        LinkedList *temp;
        HashMapElem *tmp,*new = newHashMapElem(key,data);
        if (!map||k >= map->size || k < 0) return 0;
        if (map->list[k] == NULL) {
                temp = insertElemHead(map->list[k],new);
                if (temp == NULL) return 0;
                else map->list[k] = temp;
                return 1;
        }
        else {
                aux = map->list[k];
                while (!found&&aux) {
                        tmp = (HashMapElem *) getData(aux);
                        if ((map->eq)(tmp->key,key)) found = 1;
                        else aux = nextElem(aux);
                }
                if (!found) {
                        map->list[k] = insertElemHead(map->list[k],new);
                }
                else aux->data = new;
                return 1;
        }
        return 0;
}

void * getChaining (ChainingHashMap *map, void *key) {
        int k = (map->hash)(key,map->size);
        if (!map||k >= map->size || k < 0) return NULL;
        LinkedList *aux = map->list[k];
        HashMapElem *tmp;
        int found = 0;
        while (aux&&!found) {
                tmp = getData(aux);
                if ((map->eq)(tmp->key,key)) found = 1;
                else aux = nextElem(aux);
        }
        if (aux) return tmp->data;
        else return NULL;
}

int removeChaining (ChainingHashMap *map, void *key) {
        int k = (map->hash)(key,map->size);
        if (!map||k >= map->size || k < 0) return 0;
        int found = 0;
        LinkedList *aux,*parent=NULL;
        HashMapElem *tmp;
        if (k >= map->size) return 0;
        aux = map->list[k];
        while (!found&&aux) {
                tmp = (HashMapElem *) getData(aux);
                if ((map->eq)(tmp->key,key)) found = 1;
                else {
                        parent = aux;
                        aux = nextElem(aux);
                }
        }
        if (found) {
                if (!parent) map->list[k] = NULL;
                else parent->next = aux->next;
                free(aux);
                return 1;
        }
        return 0;
}

LinkedList * keySetChaining (ChainingHashMap *map) {
	int i;
	LinkedList *result = NULL;
	LinkedList *aux = NULL;
	HashMapElem *tmp;
	for (i=0;i<map->size;i++) {
		aux = map->list[i];
		while (aux) {
			if (aux->data) {
				tmp = aux->data;
				result = insertElemHead(result,tmp->key);
			}
			aux = aux->next;
		}
	}
	return result;
}

void freeChainingHashMap (ChainingHashMap *map) {
	free(map->list);
	free(map);
}
